package mybatis;

import mybatis.entity.UserEntity;
import mybatis.service.UserService;
import mybatis.util.RandomName;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import java.lang.reflect.Method;
import java.util.Random;

/**
 * @author jackcfan
 * @date 22/9/30
 */
public class TransactionTest extends BaseTest{
  TransactionAspectSupport transactionAspectSupport;
  TransactionInterceptor transactionInterceptor;
  AbstractAutowireCapableBeanFactory abstractAutowireCapableBeanFactory;
  InfrastructureAdvisorAutoProxyCreator infrastructureAdvisorAutoProxyCreator;
  //org.springframework.aop.framework.JdkDynamicAopProxy jdkDynamicAopProxy;

  @Test
  public void transaction(){
    UserService userService = context.getBean(UserService.class);
    int age = new Random().nextInt(50);
    UserEntity user = new UserEntity()
            .setId(1L)
            .setUserName(RandomName.random().getName())
            .setAge(age)
            .setEmail("some"+age+"@one.com");
    userService.update(user);
  }

  /**
   * {@link TransactionInterceptor#invoke(MethodInvocation)}
   *
   * bean 初始化后的后置增强，对 UserService 生成代理对象
   * {@link AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization(Object, String)}
   * getBeanPostProcessors() 会有多个增强处理器，
   * 关注 {@link InfrastructureAdvisorAutoProxyCreator#postProcessAfterInitialization(Object, String)}
   *
   * 如果 UserServiceImpl 实现了接口，则使用 JDK 动态代理，否则默认使用 Cglib 生成子类代理，最终都会走到 TransactionInterceptor#invoke
   * 最终创建了一个 JDK 动态代理对象  {@link org.springframework.aop.framework.JdkDynamicAopProxy#invoke(Object, Method, Object[])}
   * 执行 UserService 任何方法时都被 JDK 动态代理，
   * {@link TransactionInterceptor#invoke(MethodInvocation)}
   *  --> {@link TransactionAspectSupport#invokeWithinTransaction(Method, Class, TransactionAspectSupport.InvocationCallback)}
   *      --> {@link TransactionAspectSupport#createTransactionIfNecessary(PlatformTransactionManager, TransactionAttribute, String)}
   *
   * */
  @Test
  public void transactionException(){
    UserService userService = context.getBean(UserService.class);
    int age = 61 + new Random().nextInt(10);
    UserEntity user = new UserEntity()
            .setId(1L)
            .setUserName(RandomName.random().getName())
            .setAge(age)
            .setEmail("some"+age+"@one.com");
    userService.update(user);
  }

  /**
   * 抛出一次，没有事务
   * {@link mybatis.service.UserServiceImpl#updateWithoutTransaction(UserEntity)} 本身没有 @Transactional 注解，所以不会被代理
   * */
  @Test
  public void withTransactionException(){
    UserService userService = context.getBean(UserService.class);
    int age = 61 + new Random().nextInt(10);
    UserEntity user = new UserEntity()
            .setId(1L)
            .setUserName(RandomName.random().getName())
            .setAge(age)
            .setEmail("some"+age+"@one.com");
    userService.updateWithoutTransaction(user);
  }
}
